package com.example.demo.controller


import com.example.demo.entity.*
import com.example.demo.repositiory.MobileWithImageRepository
import com.example.demo.repositiory.UserWithCarNumberRepository
import com.example.demo.utils.GenerateRandomCode
import com.example.demo.utils.MySessionContext
import com.example.demo.utils.WXBizDataCrypt
import com.fasterxml.jackson.databind.ObjectMapper
import com.yunpian.sdk.YunpianClient
import com.yunpian.sdk.model.Result
import com.yunpian.sdk.model.SmsSingleSend
import io.swagger.annotations.ApiImplicitParam
import io.swagger.annotations.ApiImplicitParams
import io.swagger.annotations.ApiOperation
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
import java.util.*
import javax.servlet.http.HttpServletRequest


/**
 * Created with IntelliJ IDEA.
 * Author:流年的樱花逝
 * Date:2018/11/13
 * Time:11:57
 */
@RestController
class IndexController {

    val log = LoggerFactory.getLogger(IndexController::class.java)!!

    @Autowired
    lateinit var userWithCarNumberRepository: UserWithCarNumberRepository
    @Autowired
    lateinit var mobileWithImageRepository: MobileWithImageRepository

    @Autowired
    lateinit var request: HttpServletRequest

    /**
     * 对应电脑中的存储文件夹
     */
    @Value("\${picture.location}")
    private val dir = ""

    @Value("\${picture.path}")
    private val path = ""

    /**
     * 根据手机号查询车牌号
     *  前台判断是否有数据
     *  如果有数据那么久显示列表
     *  如果没有数据那么久显示登录绑定界面
     */
    @ApiOperation(value = "根据手机号查询车牌列表")
    @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String", paramType = "query")
    @GetMapping("/fetchCarNumbers")
    fun findCarNumbersByMobile(mobile: String): ResultEntity<UserWithCarNumber> {
        return if ("" === mobile) {
            ResultEntity(200, "手机号不能为空", null, null)
        } else {
            val res = userWithCarNumberRepository.findCarNumberByMobile(mobile)
            ResultEntity(200, "success", res, null)
        }
    }


    /**
     * 发送验证码
     * 并且将数据存入数据库中
     * 并同时执行定时任务 过5分钟之后清除该手机号在数据库中对应的记录
     *
     * 增加判断手机号为空的情况
     *
     */
    @ApiOperation(value = "发送验证码到指定手机")
    @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String", paramType = "query")
    @GetMapping("/authCode")
    fun sendAuthCode(mobile: String): ResultEntity<Result<SmsSingleSend>>? {
        if ("" !== mobile) {
            val authCode = GenerateRandomCode.generate()
            val client = YunpianClient("61c7031f10a42adb6cde6d56ddc593b1").init()
            val param = client.newParam(2)
            param[YunpianClient.MOBILE] = mobile
            param[YunpianClient.TEXT] = "【北斗天汇】您的验证码是$authCode"
            val result = client.sms().single_send(param)
//        发送成功的内容存入session
            if (result.code == 0) {
                val sessionId = request.getHeader("sessionId")
                if (sessionId != null) {
                    val session = MySessionContext.getInstance().getSession(sessionId)
                    session!!.setAttribute(mobile, authCode)
                    try {
                        val timer = Timer()
                        timer.schedule(object : TimerTask() {
                            override fun run() {
                                session.removeAttribute(mobile)
                                timer.cancel()
                            }
                        }, (5 * 60 * 1000).toLong())
                    } catch (e: Exception) {
                        log.error(e.toString())
                    }
                }
            }
            client.close()
            return ResultEntity(code = 500, msg = "发送成功", res = mutableListOf(result), sessionId = null)
        } else {
            return ResultEntity(code = 500, msg = "手机号不能为空", res = null, sessionId = null)
        }

    }

    /**
     * 录入车牌号与手机号的对应关系
     *
     * 注意已经绑定的 不会再次绑定
     *
     *
     */
    @ApiOperation(value = "手机号和车牌号绑定接口")
    @ApiImplicitParams(value = [
        ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String", paramType = "query"),
        ApiImplicitParam(name = "carNumber", value = "车牌号", required = true, dataType = "String", paramType = "query"),
        ApiImplicitParam(name = "authCode", value = "验证码", required = true, dataType = "String", paramType = "query")
    ])
    @GetMapping("/binding")
    fun binding(carNumber: String, mobile: String, authCode: String): ResultEntity<UserWithCarNumber>? {
        if ("" !== carNumber && "" !== mobile && "" !== authCode) {
            val sessionId = request.getHeader("sessionId")
            val session = MySessionContext.getInstance().getSession(sessionId)
            val oldAuthCode = session!!.getAttribute(mobile)
            if (oldAuthCode !== null) {
                if (authCode == oldAuthCode.toString()) {
//            如果两个相等，那么久执行保存操作
                    val userWithCarNumber = UserWithCarNumber(null, mobile, carNumber)
                    val avibleData = userWithCarNumberRepository.findCarNumberByMobile(mobile)
                    if (avibleData.isNotEmpty()) {
                        val carList = mutableListOf<String?>()
                        for ((index, entity) in avibleData.withIndex()) {
                            carList[index] = entity.carNumber
                        }
                        if (carList.contains(carNumber)) {
                            return ResultEntity(code = 200, msg = "该手机号已经绑定该车牌号", res = null, sessionId = null)
                        } else {
                            val res = userWithCarNumberRepository.save(userWithCarNumber)
                            return ResultEntity(code = 200, msg = "保存成功", res = mutableListOf(res), sessionId = null)
                        }
                    } else {
                        val res = userWithCarNumberRepository.save(userWithCarNumber)
                        return ResultEntity(code = 200, msg = "保存成功", res = mutableListOf(res), sessionId = null)
                    }
                } else {
                    return ResultEntity(code = 500, msg = "验证码错误", res = mutableListOf(), sessionId = null)
                }
            }
            return ResultEntity(code = 500, msg = "验证码过期", res = null, sessionId = null)
        } else {
            return ResultEntity(code = 500, msg = "参数不能为空", res = null, sessionId = null)
        }

    }

    @ApiOperation(value = "上传接口")
    @ApiImplicitParam(name = "file", value = "上传文件", required = true, dataType = "File", paramType = "query")
    @PostMapping("/upload")
    fun upload(file: MultipartFile): ResultEntity<String?> {
        if (!file.isEmpty) {
            val fileName = file.originalFilename
            val savePath = "$dir/$fileName"
            log.info(savePath)
            val saveFile = File(savePath)
            if (!saveFile.parentFile.exists()) {
                saveFile.parentFile.mkdirs()
            }
//            这是返回给前台的路径
            val returnPath = "$path$fileName"
            return try {
                val out = BufferedOutputStream(FileOutputStream(saveFile))
                out.write(file.bytes)
                out.flush()
                out.close()
                ResultEntity(code = 200, msg = "上传成功", res = mutableListOf(returnPath), sessionId = null)
            } catch (e: FileNotFoundException) {
                e.printStackTrace()
                ResultEntity(code = 404, msg = "上传失败", res = mutableListOf(e.message), sessionId = null)
            } catch (e: IOException) {
                e.printStackTrace()
                ResultEntity(code = 404, msg = "上传失败", res = mutableListOf(e.message), sessionId = null)
            }
        } else {
            return ResultEntity(code = 404, msg = "上传失败,文件为空", res = mutableListOf(""), sessionId = null)
        }
    }

    @ApiOperation(value = "申诉接口")
    @ApiImplicitParams(value = [
        ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String", paramType = "query"),
        ApiImplicitParam(name = "imageUrl", value = "文件url路径", required = true, dataType = "String", paramType = "query")
    ])
    @GetMapping("/appeal")
    fun appeal(mobile: String, imageUrl: String): ResultEntity<MobileWithImage> {
        if ("" !== mobile && "" !== imageUrl) {
            val entity = MobileWithImage(id = null, mobile = mobile, url = imageUrl)
            return try {
                val res = mobileWithImageRepository.save(entity)
                ResultEntity(code = 200, msg = "保存成功", res = mutableListOf(res), sessionId = null)
            } catch (e: Exception) {
                ResultEntity(code = 404, msg = "保存失败", res = null, sessionId = null)
            }
        } else {
            return ResultEntity(code = 404, msg = "参数不能为空", res = null, sessionId = null)
        }


    }


    @ApiOperation(value = "这是给后台的不是给小程序的@小张请注意")
    @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String", paramType = "query")
    @GetMapping("/findByCarNumber")
    fun findByCarNumber(mobile: String): ResultEntity<UserWithCarNumber> {
        val result = userWithCarNumberRepository.findCarNumberByMobile(mobile)
        return ResultEntity(code = 200, msg = "查询成功", res = result, sessionId = null)
    }


    @ApiOperation(value = "这是给后台的不是给小程序的@小张请注意")
    @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String", paramType = "query")
    @GetMapping("/findUrlByMobile")
    fun findUrlByMobile(mobile: String): ResultEntity<MobileWithImage> {
        val result = mobileWithImageRepository.findUrlByMobile(mobile)
        return ResultEntity(code = 200, msg = "查询成功", res = mutableListOf(result), sessionId = null)
    }

    @ApiOperation(value = "这是给后台的不是给小程序的@小张请注意")
    @ApiImplicitParam(name = "id", value = "id号", required = true, dataType = "String", paramType = "query")
    @GetMapping("/remove")
    fun remove(id: Long): ResultEntity<Unit> {
        val result = userWithCarNumberRepository.deleteById(id)
        return ResultEntity(code = 200, msg = "查询成功", res = mutableListOf(result), sessionId = null)
    }

    /**
     *  根据小程序端传递过来的code
     *  获取对应session_key和openid
     *  这里将数据存入session中
     *
     */
    @ApiOperation(value = "发送小程序登录的code，接口改动 以后通过这个接口来获取sessionid")
    @ApiImplicitParam(name = "code", value = "code", required = true, dataType = "String", paramType = "query")
    @GetMapping("/sendCode")
    fun getCode(code: String): ResultEntity<String> {
        if ("" !== code) {
            val sessionId = request.session.id
            val session = request.session
//        这里用单例保存session
            MySessionContext.getInstance().addSession(session)
            val appId = "wx05faee1efb7f1b60"
            val secret = "42444b78de1b67e6cf9eee68dd815305"
            val code2SeesionUrl = URL("https://api.weixin.qq.com/sns/jscode2session?appid=$appId&secret=$secret&js_code=$code&grant_type=authorization_code")
            val request = code2SeesionUrl.openConnection() as HttpURLConnection
            request.requestMethod = "GET"
            request.setRequestProperty("Content-type", "application/json")
            request.instanceFollowRedirects = false
            request.connect()
            return if (request.responseCode == 200) {
                val result = getResult(request)
                session.setAttribute("wx", result)
                ResultEntity(code = 200, msg = "查询成功", res = mutableListOf(""), sessionId = sessionId)
            } else ResultEntity(code = 200, msg = "获取sessionkey失败", res = mutableListOf(""), sessionId = sessionId)
        } else {
            return ResultEntity(code = 200, msg = "参数不能为空", res = mutableListOf(""), sessionId = null)
        }

    }

    /**
     * 获取https返回的数据
     */
    @Throws(IOException::class)
    private fun getResult(connection: HttpURLConnection): String {
        val buffer = StringBuffer()
        connection.inputStream.use { inputStream ->
            InputStreamReader(inputStream).use { inputStreamReader ->
                BufferedReader(inputStreamReader).use { bufferedReader ->
                    var str: String
                    do {
                        str = bufferedReader.readLine()
                        if (str != null) {
                            buffer.append(str)
                        }
                    } while (bufferedReader.readLine() != null)
                }
            }
        }
        return buffer.toString()

    }

    /**
     * 根据小程序的加密信息 ，解密之后把手机号返回给小程序端
     */
    @Throws(IOException::class)
    @ApiOperation(value = "获取用户手机号")
    @ApiImplicitParams(value = [
        ApiImplicitParam(name = "encryptedData", value = "加密数据", required = true, dataType = "String", paramType = "query"),
        ApiImplicitParam(name = "iv", value = "加密向量", required = true, dataType = "String", paramType = "query")
    ])
    @GetMapping("/getPhone")
    fun getPhone(encryptedData: String, iv: String): ResultEntity<String> {
        if ("" !== encryptedData && "" !== iv) {
            val sessionId = request.getHeader("sessionId")
            log.debug(sessionId)
            val session = MySessionContext.getInstance().getSession(sessionId)
                    ?: return ResultEntity(code = 200, msg = "sesssion为空", res = mutableListOf(""), sessionId = null)
            val wx = session.getAttribute("wx") as String
            val wxSession = ObjectMapper().readValue(wx, WXSessionData::class.java)
            val wxBizData = WXBizDataCrypt(wxSession.session_key!!)
            val result = wxBizData.decryptData(encryptedData, iv)
            val resultObject = ObjectMapper().readValue(result, EncryptedData::class.java)
            return ResultEntity(code = 200, msg = "sesssion为空", res = mutableListOf("${resultObject.phoneNumber}"), sessionId = null)
        } else {
            return ResultEntity(code = 200, msg = "参数不能为空", res = null, sessionId = null)
        }
    }
}

